/*--------------------------------------------------------------------------------
* Copyright (c) 2022,西北农林科技大学信息学院计算机科学系
* All rights reserved.
*
* 文件名称：main.c
* 文件标识：见配置管理计划书
* 摘要：检查单词是否为变位词(相同字母的重新排列)的演示代码。
* 题目：在英语中，如果两个单词中出现的字母相同，
*       并且每个字符出现的次数也相同，
*       那么这两个单词互为变位词(Anagram)。例如：
*       slient与listen、evil与live等互为unsigned char变位词。
*
* 当前版本：1.0
* 作者：耿楠
* 完成日期：2018年12月07日
*
* 取代版本：无
* 原作者：
* 完成日期：
--------------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NUM_OF_CHARS 52

/* 函数原型 */
int is_anagram(const char *, const char *); /* 检查单词是否为变位词(映射数组算法) */
int is_word(const char *);
void create_alph_maps(const char *, int *);
void test(char **, char **, size_t n);

int main()
{
    char *p[] = {"listen", "alient" ,"live" ,"eil", "evil1"};
    char *q[] = {"slient", "listen" , "evil" ,"live", "live1"};

    test(p, q, 5);

    return 0;
}

void test(char **p, char **q, size_t n)
{
    int i, ret;

    for(i = 0; i < n; i++)
    {
        ret = is_anagram(p[i], q[i]);

        if(ret)
        {
            printf("%s and %s is angram.\n", p[i], q[i]);
        }
        else
        {
            printf("%s and %s is not angram.\n", p[i], q[i]);
        }
    }
}

/*-------------------------------------------------------------------------------------
// 名称: int is_word(const char *s)
// 功能: 检查一个字符串是否为单词
// 参数:
//       [const char *str1] --- 指向字符串的指针
// 返回: [int]  --- 1表示是变位词，0表示不是变位词
// 作者: 耿楠
// 日期: 2018年12月07日
//-------------------------------------------------------------------------------------*/
int is_word(const char *s)
{
    while(*s)
    {
        if(!((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z')))
        {
            return 0;
        }
        s++;
    }

    return 1;
}

/*-------------------------------------------------------------------------------------
// 名称: void create_alph_maps(const char *s, int *pa)
// 功能: 统计指定字符串中各字母出现的频次
// 参数:
//       [const char *s] --- 指向字符串的指针
//       [int *pa] --------- 指向字符映射数组的指针
// 返回: [void] --- 无
// 作者: 耿楠
// 日期: 2018年12月07日
//-------------------------------------------------------------------------------------*/
void create_alph_maps(const char *s, int *pa)
{
    /* 创建映射数组 */
    while (*s)
    {
        if(*s >= 'A' && *s <= 'Z')
        {
            pa[*s - 'A']++;  /* 大写字母 */
        }
        else
        {
            pa[*s - 'a' + 26]++; /* 小字字母 */
        }

        s++;
    }
}

/*-------------------------------------------------------------------------------------
// 名称: int is_anagram(const char *str1, const char *str2)
// 功能: 检查两个单词是否为变位词(相同字母的重新排列)
// 算法: 可以分别用1个一维数组统计两个字符串中每个字母出现的次数，
//       当扫描到字符串出现的每个字母时，让对应数组元素值加1。
//       最后判断两个一维数组中的元素值是否相等。
// 注意: 如果两个字符串长度不相等，则一定不是变位词。
//       如果字符串中含有非字母字符也一定不是变位词。
// 参数:
//       [const char *str1] --- 指向第1个单词的指针
//       [const char *str2] --- 指向第2个单词的指针
// 返回: [int]  --- 1表示是变位词，0表示不是变位词
// 作者: 耿楠
// 日期: 2018年12月07日
//-------------------------------------------------------------------------------------*/
int is_anagram(const char *str1, const char *str2)
{
    int i;
    int alphmaps1[NUM_OF_CHARS] = { 0 };
    int alphmaps2[NUM_OF_CHARS] = { 0 };

    /* 字符串指针为空 */
    if(str1 == NULL || str2 == NULL)
    {
        return 0;
    }

    /* 如果长度不等，则一定不是变位词 */
    if(strlen(str1) != strlen(str2))
    {
        return 0;
    }

    /* 不是单词 */
    if(!is_word(str1) || !is_word(str2))
    {
        return 0;
    }

    /* 创建映射数组，元素下标为字母编号，数组值是该字母出现的次数 */
    create_alph_maps(str1, alphmaps1);
    create_alph_maps(str2, alphmaps2);

    for(i = 0; i < 52; i++)
    {
        if(alphmaps1[i] != alphmaps2[i])
        {
            return 0; /* 如果数组值不为0，代表两个字符串中出现的字母符不完全一致，不是变位词 */
        }
    }

    return 1;
}
